package com.atguigu.gulimall.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.exception.NoWareStockException;
import com.atguigu.common.to.LockStockTo;
import com.atguigu.common.to.SkuStockTo;
import com.atguigu.common.to.mq.OrderTo;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.WareOrderTaskDetailVo;
import com.atguigu.gulimall.ware.cons.OrderRabbitConst;
import com.atguigu.gulimall.ware.dao.WareSkuDao;
import com.atguigu.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.atguigu.gulimall.ware.entity.WareOrderTaskEntity;
import com.atguigu.gulimall.ware.entity.WareSkuEntity;
import com.atguigu.gulimall.ware.feign.OrderFeignService;
import com.atguigu.gulimall.ware.feign.skuInfoFeign;
import com.atguigu.gulimall.ware.service.WareOrderTaskDetailService;
import com.atguigu.gulimall.ware.service.WareOrderTaskService;
import com.atguigu.gulimall.ware.service.WareSkuService;
import com.atguigu.gulimall.ware.vo.OrderItemVo;
import com.atguigu.gulimall.ware.vo.OrderVo;
import com.atguigu.gulimall.ware.vo.WareSkuLockTo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Data;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {
    @Autowired
    skuInfoFeign skuInfoFeign;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    WareOrderTaskService wareOrderTaskService;

    @Autowired
    WareOrderTaskDetailService wareOrderTaskDetailService;

    @Autowired
    OrderFeignService orderFeignService;


    @Override
    public void releaseStock(LockStockTo lockStockTo) {
        /**
         * 解锁的逻辑
         *   通过工作单的编号去查询该工作单是否存在
         *    存在：锁定库存成功
         *          1. 去查询订单，如果有这个订单，那么就必须解锁
         *               订单的状态为已取消：解锁
         *               未取消：不能解锁
         *          2. 订单不存在：说明订单已经回滚了，必须要解锁
         *
         *
         *
         *    不存在：锁定库存失败
         *    说明库存服务在去锁定库存的时候就已经失败了。由于方法为本地事务，所以自动就回滚了，无需解锁
         *
         */
        //库存工作单编号
        Long id = lockStockTo.getId();
        WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getById(id);
        if (wareOrderTaskEntity != null) {
            String orderSn = wareOrderTaskEntity.getOrderSn();
            R res = orderFeignService.getOrderByOrderSn(orderSn);
            if (res.getCode() == 0) {
                //远程服务调用成功
                OrderVo orderVo = res.getData(new TypeReference<OrderVo>() {
                });

                if (orderVo == null || orderVo.getStatus().equals("4")) {
                    //如果订单的状态为已关闭，那么就去回滚库存
                    //订单已经取消
                    WareOrderTaskDetailEntity detailEntity = wareOrderTaskDetailService.getOne(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", id));
                    Long skuId = detailEntity.getSkuId();
                    Long wareId = detailEntity.getWareId();
                    Integer skuNum = detailEntity.getSkuNum();
                    //冗余字段备用
                    Long taskId = detailEntity.getTaskId();
                    //释放库存
                    releaseStock(skuId, skuNum, wareId);
                    //修改库存工作单的状态为已经解锁
                    updateTaskStatus(id);
                    //手动确认消息
//                    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                }
            } else {
                throw new RuntimeException("调用服务失败~~~");
                //调用远程服务失败了，相当于这条消息就没有被消费，重新将消息放回到队列中
                //锁定库存本身就已经失败了。ack为拒绝策略  requeue:重新入队
//                channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
            }

        } else {
            //无需解锁
//            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    private void updateTaskStatus(Long id) {
        UpdateWrapper<WareOrderTaskDetailEntity> updateWrapper = new UpdateWrapper<WareOrderTaskDetailEntity>().eq("task_id", id).set("lock_status", "2");
        wareOrderTaskDetailService.update(updateWrapper);
    }


    /**
     * 释放库存
     *
     * @param skuId  商品编号
     * @param num    释放的数量
     * @param wareId 仓库编号
     */
    public void releaseStock(long skuId, Integer num, long wareId) {
        baseMapper.releaseStock(skuId, num, wareId);
    }


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryByCondition(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        //skuId: 48
        //wareId: 1
        String skuId = (String) params.get("skuId");
        if (!StringUtils.isEmpty(skuId)) {
            wrapper.eq("sku_id", skuId);
        }

        String wareId = (String) params.get("wareId");
        if (!StringUtils.isEmpty(wareId)) {
            wrapper.eq("ware_id", wareId);
        }

        IPage<WareSkuEntity> page = this.page(new Query<WareSkuEntity>().getPage(params), wrapper);
        return new PageUtils(page);
    }

    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        //商品添加库存
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("sku_id", skuId).eq("ware_id", wareId);
        WareSkuEntity skuEntity = this.baseMapper.selectOne(wrapper);

        //新增
        if (skuEntity == null) {
            WareSkuEntity wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(skuId);
            R info = skuInfoFeign.info(skuId);
            Map<String, Object> skuInfo = (Map<String, Object>) info.get("skuInfo");
            String skuName = (String) skuInfo.get("skuName");
            //调用远程服务查询
            wareSkuEntity.setSkuName(skuName);
            wareSkuEntity.setStock(skuNum);
            wareSkuEntity.setWareId(wareId);

            //保存记录
            this.save(wareSkuEntity);

        } else {
            //在原有的记录上做更新操作
            baseMapper.updateStock(skuId, wareId, skuNum);
        }


    }

    @Override
    public List<SkuStockTo> hashStock(List<Long> skuIds) {
        List<SkuStockTo> stockToList = skuIds.stream().map(skuId -> {
            Integer count = baseMapper.selectSkuStock(skuId);
            SkuStockTo skuStockTo = new SkuStockTo();
            skuStockTo.setSkuId(skuId);
            skuStockTo.setHasStock(count == null ? false : count > 0);
            return skuStockTo;
        }).collect(Collectors.toList());

        return stockToList;
    }

    @Transactional
    @Override
    public Boolean lockStock(WareSkuLockTo wareSkuLockTo) {
        //将要发送到延时队列的消息内容
        LockStockTo lockStockTo = new LockStockTo();
        //设置订单编号
        lockStockTo.setOrderSn(wareSkuLockTo.getOrderSn());
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        //插入库存工作单
        wareOrderTaskEntity.setOrderSn(wareSkuLockTo.getOrderSn());
        wareOrderTaskEntity.setCreateTime(new Date());
        wareOrderTaskService.save(wareOrderTaskEntity);

        lockStockTo.setId(wareOrderTaskEntity.getId());


        //锁定库存
        List<OrderItemVo> locks = wareSkuLockTo.getLocks();
        //将当前商品的库存信息收集起来
        List<SkuWareHashStock> collect = locks.stream().map(item -> {
            SkuWareHashStock skuWareHashStock = new SkuWareHashStock();
            skuWareHashStock.setSkuId(item.getSkuId());
            skuWareHashStock.setNum(item.getCount());
            //该属性要经过查询才能得到
            List<Long> wareIds = this.baseMapper.listWareIds(item.getSkuId());
            skuWareHashStock.setWareIds(wareIds);
            return skuWareHashStock;
        }).collect(Collectors.toList());


        //锁定
        for (SkuWareHashStock skuWareHashStock : collect) {
            boolean skuStocked = false;
            if (StringUtils.isEmpty(skuWareHashStock.getWareIds())) {
                //米有该商品
                throw new NoWareStockException(skuWareHashStock.getSkuId());
            }
            List<Long> wareIds = skuWareHashStock.getWareIds();
            for (Long wareId : wareIds) {
                Integer count = this.baseMapper.lockStock(skuWareHashStock.getSkuId(), wareId, skuWareHashStock.getNum());
                if (count > 0) {
                    skuStocked = true;
                    //修改成功,不让再修改了
                    WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
                    wareOrderTaskDetailEntity.setSkuId(skuWareHashStock.getSkuId());
                    wareOrderTaskDetailEntity.setSkuNum(skuWareHashStock.getNum());
                    wareOrderTaskDetailEntity.setTaskId(wareOrderTaskEntity.getId());
                    wareOrderTaskDetailEntity.setLockStatus(1);
                    wareOrderTaskDetailEntity.setWareId(wareId);
                    WareOrderTaskDetailVo wareOrderTaskDetailVo = new WareOrderTaskDetailVo();
                    //保存库存工作单详情的数据
                    wareOrderTaskDetailService.save(wareOrderTaskDetailEntity);
                    //属性对拷
                    BeanUtils.copyProperties(wareOrderTaskDetailEntity, wareOrderTaskDetailVo);
                    //完善消息体的数据
                    lockStockTo.setWareOrderTaskDetailEntity(wareOrderTaskDetailVo);
                    //ToDO:发送锁定库存成功的消息到延时队列中
                    rabbitTemplate.convertAndSend(OrderRabbitConst.EVENT_EXCHANGE, OrderRabbitConst.DELAY_ROUTE_KEY, lockStockTo);

                    break;
                } else {
                    //继续修改
                }
            }

            if (!skuStocked) {
                //抛出异常，修改失败
                throw new NoWareStockException(skuWareHashStock.getSkuId());
            }

        }

        //能走到这里都是修改成功的
        return true;
    }

    @Data
    class SkuWareHashStock {

        private long skuId;
        //锁定数量
        private Integer num;
        //分布的仓库
        List<Long> wareIds;
    }


    /**
     * 释放库存
     *
     * @param order
     */
    @Transactional
    @Override
    public void releaseStock(OrderTo order) {
        String orderSn = order.getOrderSn();
        WareOrderTaskEntity orderTaskEntity = wareOrderTaskService.getOne(new QueryWrapper<WareOrderTaskEntity>().eq("order_sn", orderSn));
        Long id = orderTaskEntity.getId();
        //库存工作单详情
//        WareOrderTaskDetailEntity wareOrderTaskDetailEntity = wareOrderTaskDetailService.getOne(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", id));
        //未释放的且满足条件的库存
        List<WareOrderTaskDetailEntity> taskDetailEntityList = wareOrderTaskDetailService.list(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", id).eq("lock_status", 1));
        for (WareOrderTaskDetailEntity wareOrderTaskDetailEntity : taskDetailEntityList) {
            //修改释放的状态为已经释放
            wareOrderTaskDetailEntity.setLockStatus(2);
            wareOrderTaskDetailService.updateById(wareOrderTaskDetailEntity);
            //释放库存
            this.releaseStock(wareOrderTaskDetailEntity.getSkuId(), wareOrderTaskDetailEntity.getSkuNum(), wareOrderTaskDetailEntity.getWareId());
        }


    }
}